# MazePlayerAI.py: automatically moves the player to a destination
# Written by Victor Luna Freire - victorclf@live.com
# Copyright (c) Victor Luna Freire. All rights reserved.
# Wednesday, November 04, 2009 6:29:09 PM
# Python 2.6.2

import Defines
import Renderer
import Shared


class MazePlayerAI:
    def __init__(self, player_to_control):
        self.angle_speed = Defines.DEFAULT_MAZE_PLAYER_AI_TURN_SPEED
        self.move_speed = Defines.DEFAULT_MAZE_PLAYER_AI_MOVE_SPEED
        self.player = player_to_control
        self.turn_right = None
        self.dest_pos = None
        self.dest_angle = None
        self.backward = False
        
    
    def adjust_to_interval(self, value, interval):
        ''' Check if a value is in a certain range. If it is not, set it to the maximum or minimum value possible in the range. '''
        if value > interval[1]:
            value = interval[1]
            return True
        elif value < interval[0]:
            value = interval[0]
            return True
        return False
        
    
    def adjust_speed(self, angle_speed, move_speed):
        ''' Adjust the move and turn speed for this player controller AI. '''
        self.angle_speed += angle_speed
        self.move_speed += move_speed
        self.adjust_to_interval(self.angle_speed, Defines.MAZE_PLAYER_AI_TURN_SPEED_INTERVAL)
        self.adjust_to_interval(self.move_speed, Defines.MAZE_PLAYER_AI_MOVE_SPEED_INTERVAL)
        return (self.angle_speed, self.move_speed)
        
        
    def turn(self, mult_factor):
        ''' Turn to the desired angle. '''
        if self.dest_angle is None or self.player.angle == float(self.dest_angle): return False #finished turning
        
        angle_var = self.angle_speed * mult_factor
        angle_diff = abs(self.player.angle - self.dest_angle)
                
        if angle_diff <= angle_var:
            # Finished turning
            self.player.angle = self.dest_angle
        else:
            # Keep turning
            if self.turn_right:
                self.player.turn_right_angle(angle_var)
            else:
                self.player.turn_left_angle(angle_var)
                
        return True
        
    
    def move(self, mult_factor):
        ''' Move to the desired direction. '''
        if not self.dest_pos: return False #finished moving
        
        dist_var = self.move_speed * mult_factor
        dist_diff = Renderer.distance_points_ang(self.player.x, self.player.y, self.dest_pos[0], self.dest_pos[1], self.dest_angle)
        
        if dist_diff <= dist_var:
            # Finished moving
            self.player.x = self.dest_pos[0]
            self.player.y = self.dest_pos[1]
            self.dest_pos = None
        else:
            # Keep moving
            self.player.move_to_unchecked(self.player.angle, mult_factor, self.move_speed)
        
        return True
    
    
    def set_destination(self, pos, backward):
        self.player.angle %= 360
        self.dest_pos = Shared.gridcenter((pos[0], pos[1]))
        self.dest_angle = int(Renderer.angle_points(self.player.x, self.player.y, self.dest_pos[0], self.dest_pos[1])) % 360
        self.backward = backward
        angdiff = (self.player.angle - self.dest_angle)
        if angdiff >= 0: 
            self.turn_right = (angdiff <= 180)
        else:
            self.turn_right = (abs(angdiff) > 180)
    
    def stop_moving(self):
        self.dest_angle = self.player.angle
        self.dest_pos = (self.player.x, self.player.y)
    
    
    def teleport(self, pos):
        self.player.x = pos[0]
        self.player.y = pos[1]
        self.player.angle = 270
        self.stop_moving()
                
        
    def main(self, mult_factor):
        # Execute actions in order of priority
        if (self.turn(mult_factor)  # Turn to face the destination point if not facing yet
        or self.move(mult_factor)): # Move towards the destination point if not there yet
            return True 
        return False
            
                
        
        
        